﻿using MiniFox.Infrastructure.Attributes;
using MiniFox.Utility;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Data;
using System.Linq;
using System.Reflection;
using System.Text;

namespace MiniFox.Infrastructure
{
    /// <summary>
    /// 
    /// </summary>
    [Serializable, JsonObject]
    public class ViewTable
    {
        ViewColumnCollection _columns;
        ViewRowCollection _rows;
        List<ViewRow> _rowList;
        string _tableName;
        /// <summary>
        /// 
        /// </summary>
        public ViewTable() : this(string.Empty)
        {
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="tableName"></param>
        public ViewTable(string tableName)
        {
            _tableName = tableName;
            _columns = new ViewColumnCollection();
            _rowList = new List<ViewRow>();
            _rows = new ViewRowCollection(this);
        }
        internal List<ViewRow> RowList
        {
            get
            {
                return _rowList;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("name")]
        public string Name
        {
            get
            {
                return _tableName;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("columns")]
        public virtual ViewColumnCollection Columns
        {
            get { return _columns; }
        }
        /// <summary>
        /// 
        /// </summary>
        [JsonProperty("rows")]
        public virtual ViewRowCollection Rows
        {
            get
            {
                return _rows;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public ViewRow NewRow()
        {
            var row = new ViewRow(_columns);
            return row;
        }


        #region static members
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public static ViewTable CreateViewTable<T>()
        {
            return CreateViewTable<T>(string.Empty);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tableName"></param>
        /// <returns></returns>
        public static ViewTable CreateViewTable<T>(string tableName)
        {
            Type genType = typeof(T);
            var viewTable = new ViewTable(tableName);
            var properties = genType.GetProperties();
            foreach (PropertyInfo property in properties)
            {
                string sourceName = property.Name;
                ColumnAttribute columnAttribute = property.GetCustomAttribute<ColumnAttribute>();
                string name = columnAttribute == null ? sourceName : columnAttribute.Name;
                ViewColumn col;
                if (viewTable.Columns.Contains(name))
                {
                    col = viewTable.Columns[name];
                }
                else
                {
                    col = new ViewColumn(name, sourceName);
                    viewTable.Columns.Add(col);
                }
                KeyAttribute keyAttr = property.GetCustomAttribute<KeyAttribute>();
                col.IsKey = keyAttr != null;

                DisplayAttribute displayAttr = property.GetCustomAttribute<DisplayAttribute>();
                if (displayAttr == null)
                {
                    col.DisplayName = sourceName;
                }
                else
                {
                    col.DisplayName = string.IsNullOrWhiteSpace(displayAttr.ShortName) ? displayAttr.Name : displayAttr.ShortName;
                    col.Ordinal = displayAttr.Order;
                }

                var dataTypeAttr = property.GetCustomAttribute<DataTypeAttribute>();
                if (dataTypeAttr != null)
                {
                    if (string.IsNullOrEmpty(dataTypeAttr.CustomDataType))
                    {
                        col.DataType = dataTypeAttr.DataType.ToString();
                    }
                    else
                    {
                        col.DataType = dataTypeAttr.CustomDataType;
                    }
                }
                else
                {
                    TypeCode typeCode = Type.GetTypeCode(property.PropertyType);
                    string dataType = "string";
                    switch (typeCode)
                    {
                        case TypeCode.Int16:
                        case TypeCode.Int32:
                        case TypeCode.Int64:
                        case TypeCode.Single:
                        case TypeCode.Double:
                        case TypeCode.Decimal:
                        case TypeCode.Byte:
                        case TypeCode.SByte:
                        case TypeCode.UInt16:
                        case TypeCode.UInt32:
                        case TypeCode.UInt64:
                            dataType = "number";
                            break;
                        case TypeCode.Boolean:
                            dataType = "boolean";
                            break;
                        case TypeCode.DateTime:
                            dataType = "datetime";
                            break;
                        case TypeCode.Char:
                        case TypeCode.String:
                            dataType = "string";
                            break;
                        default:
                            break;
                    }
                    col.DataType = dataType;
                }
                var formatAttr = property.GetCustomAttribute<DisplayFormatAttribute>();
                if (formatAttr != null)
                {
                    col.DisplayFormat = formatAttr.DataFormatString;
                }

            }
            return viewTable;
        }

        #endregion
    }
}
